﻿using System;
using System.Diagnostics.Contracts;
using System.IO;

namespace OpenLS.Spreadsheet.Formats.Biff.Records
{
    internal class PARAMQRY_Fixed
    {
        private ushort fVal;
        public ushort grbit;
        private ODBCType wTypeSql;
        private bool unused1;
        private bool fNonDefaultName;
        internal int pbt;

        public void Read(BinaryReader reader)
        {
            wTypeSql = (ODBCType) reader.ReadUInt16();
            var pbtab = reader.ReadUInt16();
            this.pbt = (pbtab & 0x3);
            this.unused1 = (pbtab & 0x04) != 0;
            this.fNonDefaultName = (pbtab & 0x08) != 0;
            grbit = reader.ReadUInt16();
            fVal = reader.ReadUInt16();
        }
    }

    internal abstract class ItemQueryBase
    {
        public abstract void Read(BinaryReader reader);
    }

    internal class SXString
    {
        private ushort cch;
        private XLUnicodeStringNoCch segment;

        public void Read(BinaryReader reader)
        {
            cch = reader.ReadUInt16();
            if (0xFFFF != cch )
            {
                segment = new XLUnicodeStringNoCch();
                segment.Read(reader, cch);
            }
        }
    }

    internal class FMSER_param
    {
        private ushort cce;
        private byte[] rgce;

        public void Read(BinaryReader reader)
        {
            cce = reader.ReadUInt16();
            rgce = reader.ReadBytes(cce);
        }
    }

    internal class DbQuery : ItemQueryBase
    {
        private PARAMQRY_Fixed _fixed;
        private object rgb;

        public override void Read(BinaryReader reader)
        {
            _fixed = new PARAMQRY_Fixed();
            _fixed.Read(reader);
            switch (_fixed.pbt)
            {
                case 0:
                    {
                        var SXString = new SXString();
                        SXString.Read(reader);
                        reader.ReadByte();
                        rgb = SXString;
                    }
                    break;
                case 1:
                    {
                        switch (_fixed.grbit)
                        {
                            case 1:
                                rgb = reader.ReadDouble();
                                break;
                            case 2:
                                {
                                    var SXString = new SXString();
                                    SXString.Read(reader);
                                    reader.ReadByte();
                                    rgb = SXString;
                                }
                                break;
                            case 3:
                                rgb = reader.ReadInt32();
                                break;
                            default:
                                throw new NotSupportedException();
                        }
                    }
                    break;
                case 2:
                    {
                        var FMSER_param = new FMSER_param();
                        FMSER_param.Read(reader);
                        rgb = FMSER_param;
                    }
                    break;
                default:
                    throw new NotSupportedException();
            }
        }
    }

    internal class ParamQry : ItemQueryBase
    {
        private PARAMQRY_Fixed _fixed;
        private object rgb;

        public override void Read(BinaryReader reader)
        {
            _fixed = new PARAMQRY_Fixed();
            _fixed.Read(reader);
            switch (_fixed.pbt)
            {
                case 0:
                    {
                        var SXString = new SXString();
                        SXString.Read(reader);
                        reader.ReadByte();
                        rgb = SXString;
                    }
                    break;
                case 1:
                    {
                        switch (_fixed.grbit)
                        {
                            case 1:
                                rgb = reader.ReadDouble();
                                break;
                            case 2:
                                {
                                    var SXString = new SXString();
                                    SXString.Read(reader);
                                    reader.ReadByte();
                                    rgb = SXString;
                                }
                                break;
                            case 0x800:
                                rgb = reader.ReadInt32();
                                break;
                            default:
                                throw new NotSupportedException();
                        }
                    }
                    break;
                case 2:
                    {
                        var FMSER_param = new FMSER_param();
                        FMSER_param.Read(reader);
                        rgb = FMSER_param;
                    }
                    break;
                default:
                    throw new NotSupportedException();
            }
        }
    }


internal class DbOrParamQryRecord : BiffRecord
{
    private ItemQueryBase rgb;

    internal override BiffRecordType RecordType
    {
        get { return BiffRecordType.DbOrParamQry; }
    }

    protected override void ReadContent(BiffReaderContext context, int length)
    {
#if DEBUG
        long pos = context.BaseStream.Position;
#endif

        BiffRecord previous = context.PreviousRecord;
        if (previous is SXStringRecord)
        {
            rgb = new ParamQry();
        }
        else if (previous is DbOrParamQryRecord)
        {
            throw new NotImplementedException();
        }
        else
        {
            rgb = new DbQuery();
        }
        rgb.Read(context.Reader);
#if DEBUG
        Contract.Assert(context.BaseStream.Position - pos == length);
#endif

    }

    internal override void WriteContent(BiffWriterWorkbookContext context)
    {
        throw new NotImplementedException();
    }
}

}